AI 看得懂
if、看得懂 SQL,也能一路追到資料表。
但它未必知道:為什麼這個條件不能拿掉?
前一篇,我們把 AI 的分析一路追到:
畫面元件
↓
Dataset
↓
SQL / Stored Procedure
↓
資料表與欄位
做到這裡,我原本以為已經很接近「看懂系統」。
但真正開始修改 ERP 之後,我才發現:
找到資料從哪裡來,只回答了「系統怎麼做」。
更難的是「公司為什麼要這樣做」。
例如:
if dtDocument.FieldByName('STATUS').AsString = 'N' then
btnEdit.Enabled := True;
AI 很容易解釋:
STATUS = 'N'時,系統允許使用者編輯資料。
語法完全沒問題。
但如果它接著說:
N代表「未簽核」,所以未簽核單據都可以修改。
事情就開始危險了。
因為程式碼目前只能證明:
STATUS = N
↓
btnEdit.Enabled = True
它沒有證明:
N = 未簽核
更沒有證明:
所有 STATUS = N 的資料都一定允許修改
這也是 Legacy System 最麻煩的地方。
AI 很會讀 Code。
但 Business Rule 往往根本沒有完整寫在 Code 裡。
先把兩件事情拆開。
程式邏輯回答的是:
如果 A 成立
↓
執行 B
例如:
if Status = 'N' then
AllowEdit;
AI 對這種事情通常很擅長。
它可以解釋條件、追 Function、找變數,甚至幫我們畫出執行流程。
但 Business Rule 問的是另一件事:
為什麼 A 成立時才能執行 B?
這個「為什麼」,才是真正困難的地方。
理想狀況下,一條商業規則應該有:
需求文件
↓
Business Rule
↓
程式實作
↓
測試案例
但很多維護十幾年以上的系統,比較常見的是:
一部分在 Delphi
一部分在 Stored Procedure
一部分在 Trigger
一部分藏在資料欄位
還有一部分只存在資深使用者的記憶裡
例如「這張單據能不能修改」,可能同時受到:
| 位置 | 可能包含的規則 |
|---|---|
| Delphi UI | Edit Button 是否 Enabled |
| Dataset Event | Post 前是否再次檢查 |
| Stored Procedure | 是否允許更新目前狀態 |
| Trigger | 阻止不合法資料異動 |
| 資料欄位 | 簽核、鎖定、作廢狀態 |
| 使用者流程 | 某些情況即使畫面能操作,也不能真的修改 |
所以 Search 到:
STATUS = 'N'
只能證明:
這個條件存在。
不能直接推論:
這就是完整的 Business Rule。
Legacy System 裡經常看到這種欄位:
MARK_1
MARK_2
STATUS
TYPE
LOCK_FLAG
YN
SEQ
有些欄位甚至連維護它很多年的人,都不敢只看名字解釋。
可是 AI 很容易根據名稱建立一個「看起來很合理」的故事。
例如看到:
if LOCK_FLAG = '' then
它可能直接解釋:
LOCK_FLAG為空代表資料尚未鎖定,因此使用者可以修改。
問題是:
合理,不等於正確。
假設我第一次只把這段程式丟給 AI:
procedure TFDocument.btnEditClick(Sender: TObject);
begin
if dtDocument.FieldByName('LOCK_FLAG').AsString <> '' then
begin
ShowMessage('目前資料無法修改。');
Exit;
end;
dtDocument.Edit;
end;
然後問:
請解釋 LOCK_FLAG 的用途,以及這段程式的商業規則。
AI 很可能回答得像這樣:
LOCK_FLAG是資料鎖定旗標。
空字串表示資料目前沒有被鎖定,因此允許使用者修改。非空字串代表資料已被其他使用者或流程鎖定,所以系統會阻止編輯,以避免多人同時修改造成資料衝突。
這段回答最大的問題,不是它一定錯。
而是:
它把沒有證據的假設,講成已經確認的事實。
拆開來看會更清楚。
LOCK_FLAG <> ''
↓
不允許進入 Edit
LOCK_FLAG 是多人編輯鎖
非空值代表其他使用者正在使用
這個設計是為了避免 concurrency
這些都有可能是真的。
但目前沒有任何證據。
這就是最危險的地方。
如果 AI 回答:
「我不知道。」
我們反而會繼續查。
但它偏偏給了一個非常合理、非常完整、甚至很像資深工程師寫出來的解釋。
工程師一旦沒有再往下驗證,就可能直接把假設當成規格。
接著我繼續搜尋相關程式。
又找到:
procedure TFDocument.dtDocumentAfterScroll(DataSet: TDataSet);
begin
btnEdit.Enabled :=
dtDocument.FieldByName('STATUS').AsString = 'N';
end;
現在至少知道:
STATUS = N
↓
Edit Button 才能按
但按下之後還會:
LOCK_FLAG <> ''
↓
阻止 Edit
整條流程變成:
STATUS = N
↓
Edit Button Enabled
↓
使用者按 Edit
↓
檢查 LOCK_FLAG
↓
LOCK_FLAG = ''
↓
dtDocument.Edit
所以一開始:
STATUS = N → 可以修改
是不完整的。
比較精確應該是:
STATUS = N
AND
LOCK_FLAG = ''
↓
目前這個畫面的 Edit 入口允許修改
我刻意寫:
「目前這個畫面的 Edit 入口」
而不是:
「整套 ERP 都允許修改」
因為現在仍然沒有證明:
這次我不再問:
LOCK_FLAG 是什麼?
而是改成:
請根據目前提供的程式碼整理 Business Rule。
規則:
1. 只能列出有程式碼證據支持的結論。
2. 每一條結論要標示證據來源。
3. 根據欄位名稱推測的內容必須標示為「假設」。
4. 沒有足夠證據的地方列入「待確認」。
5. 不要自行補完欄位的商業意義。
這次我期待 AI 回答的是:
已確認
STATUS = 'N'時,btnEdit會被設為 Enabled。
證據:dtDocumentAfterScroll使用者按下 Edit 後,如果
LOCK_FLAG <> '',程式會停止,不會執行dtDocument.Edit。
證據:btnEditClick因此目前這個畫面的編輯入口至少受到
STATUS與LOCK_FLAG兩個條件影響。假設
LOCK_FLAG可能與資料鎖定或流程狀態有關,但目前程式碼不足以判斷其完整商業意義。待確認
STATUS = 'N'的實際業務定義。LOCK_FLAG各個可能值的意義。- 是否存在其他編輯入口。
- Stored Procedure 或 Trigger 是否還有額外限制。
兩次回答放在一起看,差異其實非常明顯。
| 第一次回答 | 加入限制後 |
|---|---|
LOCK_FLAG 是資料鎖 |
LOCK_FLAG 的商業意義尚未確認 |
| 非空代表其他人正在使用 | 只能確認非空時阻止 Edit |
| 目的為避免多人修改 | 原因目前沒有證據 |
| 把推測寫成結論 | 把內容拆成已確認、假設、待確認 |
AI 並沒有突然獲得更多公司知識。
真正改變的是:
我不再允許它把空白的地方自己補滿。
第一次:
LOCK_FLAG是防止多人同時修改資料的鎖定機制。
第二次:
LOCK_FLAG <> ''會阻止目前這個 Edit 流程。至於LOCK_FLAG是否代表多人編輯鎖,目前沒有足夠證據。
第二個答案才可以繼續往下用。
不是因為它說得比較完整。
而是因為它很清楚地區分:
已知
假設
未知
這三個層級。
第一個答案最大的問題不是一定錯。
而是:
AI 把「可能」講成了「就是」。
所以現在遇到比較重要的商業規則,我會要求 AI 幫我整理成一張 Rule Card。
例如:
| 項目 | 內容 |
|---|---|
| Rule ID | BR-EDIT-001 |
| 行為 | 控制目前資料是否可進入編輯 |
| 已確認條件 | STATUS = 'N' |
| 第二層條件 | LOCK_FLAG = '' |
| 證據 | AfterScroll、btnEditClick |
| 未確認 | STATUS = 'N' 的完整商業意義 |
| 未確認 | LOCK_FLAG 每個值代表什麼 |
| 未確認 | 是否存在其他編輯入口 |
| 修改風險 | 可能影響既有資料修改權限 |
| 驗證方式 | 測試不同 STATUS / LOCK_FLAG 組合 |
Rule Card 真正有價值的地方,不是文件變漂亮了。
而是強迫我們回答四件事:
我知道什麼?
↓
我從哪裡知道?
↓
哪些只是推測?
↓
還有哪些不知道?
而且這張卡片不會停在這裡。
下一步我會直接把它再次交給 AI,當成新的 Context:
根據 BR-EDIT-001,目前還有以下待確認事項:
1. STATUS = N 的完整意義
2. LOCK_FLAG 各值的用途
3. 是否存在其他修改入口
4. Stored Procedure / Trigger 是否有額外限制
請只針對以上未知項目繼續追查,
並為每個結論提供程式碼或 SQL 證據。
接著可能去:
搜尋 Stored Procedure
↓
查看 Trigger
↓
檢查其他 Form
↓
比對歷史資料
↓
詢問資深使用者
↓
把確認結果更新回 Rule Card
這樣 Rule Card 就不是一次性的分析結果。
它會變成一份持續更新的:
Business Rule Context。
每確認一件事,就把「未知」移到「已確認」。
每發現新的問題,就繼續加入「待確認」。
最後得到的不是 AI 自己編出來的規格書,而是:
一份有證據逐步長出來的規格。
上一篇我們建立的是:
UI
↓
Dataset
↓
SQL
↓
Database
但 Business Rule 還要繼續往外追:
程式條件
↓
其他呼叫位置
↓
相關欄位
↓
Stored Procedure / Trigger
↓
實際操作流程
↓
歷史資料
↓
使用者或需求確認
不代表每個問題都必須一路查到底。
但規則越重要,我就會要求越多證據。
特別是碰到:
金額
簽核
權限
刪除
編號
狀態
跨資料表同步
這些地方時,更不能只憑一段 Code 就宣布:
「我找到 Business Rule 了。」
第三篇建立 Context Pack 時,我們整理過:
問題現象
↓
操作步驟
↓
錯誤訊息
↓
相關 Event
↓
Dataset / SQL
↓
Schema
現在我會再補上一塊:
Business Rules
而且不只是放「已知規則」。
還要把「未知」一起寫進去。
例如:
【已知商業規則】
1. STATUS = 'N' 時,目前畫面的 Edit Button 可以按。
2. 實際進入 Edit 前,
還會檢查 LOCK_FLAG 是否為空。
3. 本次需求只允許調整 Edit 判斷,
不允許修改其他流程。
【目前未知】
1. STATUS = 'N' 的完整業務定義。
2. LOCK_FLAG 所有可能值的意義。
3. 是否還有其他畫面可以修改同一筆資料。
4. Database 是否還有第二層防護。
【AI 回答限制】
對未知事項不得自行推論為既定規則;
若需要做假設,必須明確標記為「假設」。
以前我會覺得:
Prompt 裡寫「不知道」,是不是代表提供的 Context 不夠完整?
現在我反而認為:
能夠明確指出自己不知道什麼,本身就是 Context Engineering 的一部分。
因為最危險的不是資料不足。
而是:
資料不足
+
AI 自動補完
+
工程師沒發現它在猜
當 AI 覺得自己已經理解 Business Rule,很容易開始提出:
建議把 LOCK_FLAG 改成 Boolean。
建議把 STATUS 統一改成 Enum。
建議把這些判斷集中成一個 Method。
建議移除重複條件。
建議重新整理整套狀態管理。
從程式設計角度看,很多建議甚至沒有錯。
問題是它不知道:
Legacy System 有一個很麻煩的特性:
今天看起來像 Bug 的東西,十年後可能已經變成 Business Rule。
所以在證明以前,我不希望 AI 因為:
「這樣寫比較漂亮。」
就把它順手改掉。
這篇其實幾乎跟 Delphi 無關。
不論維護 Java、C#、PHP、Python、COBOL,或任何企業舊系統,都可以帶走三件事。
STATUS = N
是程式事實。
N = 未簽核
則需要另外證明。
找到一個條件只是線索。
真正的規則可能散落在:
UI
Database
Workflow
Historical Data
User Knowledge
如果證據不足:
「目前無法確認。」
不是一個差答案。
反而可能是 Legacy System 裡最安全的答案之一。
前六天,我一直在想辦法讓 AI 看懂 Legacy Code。
到了今天,我反而開始覺得:
語法可能是整套 Legacy System 裡最簡單的部分。
真正困難的是:
這個欄位為什麼存在?
這個判斷為什麼不能拿掉?
十年前的資料是不是例外?
還有沒有另一條流程?
這到底是程式設計,
還是已經變成公司規則?
所以今天替 AI Agent 再增加一條規則:
不要只告訴我 Code 在做什麼。
請把「已確認」、「假設」與「未知」分開。
因為維護 Legacy System 時,最危險的 AI 不一定是回答錯誤。
而是:
它只看到一小段 Code,卻替整套系統寫出了一個非常合理的故事。
下一篇,就要開始碰一個很典型的 ERP 問題。
需求聽起來只有一句:
「這個編號規則要改一下。」
但真的開始往下追之後才會發現:
你以為只是在改一個欄位,實際上可能動到主檔、明細、簽核、報表,甚至整條資料生命週期。